#include "main.h"
#include "Chat.h"

/*
 * dlgServerProc
 * - Message handler for "server" window
 */
BOOL CALLBACK dlgServerProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static int nMaxUsers = 0;		// Max users to be connected (+ 1, to compensate for "0" socket)
	static int nPort = 0;			// Port to listen on
	static char *szServerID = NULL; // Null-Terminated string User ID for server

	switch (msg)
	{
	case WM_INITDIALOG:
		{
			/*
			 * Center on screen
			 */
			CenterOnScreen(hWnd);
			
			/*
			 * Process parameters
			 */
			dlgReturn *dataReturn = (dlgReturn *)lParam;

			nMaxUsers = dataReturn->params[0] + 1;
			nPort = dataReturn->params[1];
			szServerID = (char *)dataReturn->params[2];

			/*
			 * Start winsock
			 */
			if (!WinsockStart(nMaxUsers))
			{
				EndDialog(hWnd, 1);
				return TRUE;
			}

			/*
			 * Disable File => Stop
			 */
			EnableMenu(GetMenu(hWnd), IDM_FILE_STOP, FALSE);

			/*
			 * Add ourself to users connected list
			 */
			SendDlgItemMessage(hWnd, IDC_USERS, LB_ADDSTRING, 0, (LPARAM)szServerID);
		}
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		/*
		 * File => Start
		 */
		case IDM_FILE_START:
			{
				char *sysmsg = (char *)malloc(32);
				sprintf(sysmsg, "Starting server on port %d", nPort);
				AddSystemText(GetDlgItem(hWnd, IDC_RICHEDIT), sysmsg);
				free(sysmsg);

				/*
				 * Begin listening
				 */
				char *szBufServerID = (char *)malloc(strlen(szServerID) + 1);
				strcpy(szBufServerID, szServerID);
				if (!WinsockOpen() || !WinsockListen(hWnd, nPort, szBufServerID))
					EndDialog(hWnd, 1);

				/*
				 * Disable File => Start
				 * Enable File => Stop
				 */
				EnableMenu(GetMenu(hWnd), IDM_FILE_START, FALSE);
				EnableMenu(GetMenu(hWnd), IDM_FILE_STOP);
			}
			break;

		/*
		 * File => Stop
		 */
		case IDM_FILE_STOP:
			AddSystemText(GetDlgItem(hWnd, IDC_RICHEDIT), "Kicking users and stopping server");

			/*
			 * Close all sockets
			 */
			if (!WinsockClose(nMaxUsers))
				EndDialog(hWnd, 1);

			/*
			 * Enable File => Start
			 * Disable File => Stop
			 */
			EnableMenu(GetMenu(hWnd), IDM_FILE_STOP, FALSE);
			EnableMenu(GetMenu(hWnd), IDM_FILE_START);
			break;

		/*
		 * File => Exit
		 */
		case IDM_FILE_EXIT:
			/*
			 * Send close message
			 */
			SendMessage(hWnd, WM_CLOSE, 0, 0);
			break;

		/*
		 * Send Button
		 */
		case IDC_SEND:
			{
				/*
				 * Make sure user entered text
				 */
				int nLength = GetWindowTextLength(GetDlgItem(hWnd, IDC_EDIT_MSG));
				if (nLength > 0)
				{
					char *szMsg = (char *)malloc(nLength + 1);
					GetDlgItemText(hWnd, IDC_EDIT_MSG, szMsg, nLength + 1);

					/*
					 * Get color data for user
					 */
					COLORREF *crText = (COLORREF *)malloc(sizeof(COLORREF));
					WinsockGetColor(szServerID, nMaxUsers, crText);

					/*
					 * Send and add message
					 */
					ChatSendMsg(szServerID, *crText, szMsg, nMaxUsers);
					AddChatMsg(GetDlgItem(hWnd, IDC_RICHEDIT), szServerID, *crText, szMsg);

					free(crText);
					free(szMsg);

					/*
					 * Clear edit box
					 */
					SetDlgItemText(hWnd, IDC_EDIT_MSG, "");
				}
			}
			break;
		}
		break;

	case WM_SOCKET_ASYNC:
		switch (WSAGETSELECTEVENT(lParam))
		{
		case FD_READ:
			{
				/*
				 * Read command
				 */
				char *type = (char *)malloc(5);
				WinsockReadType((SOCKET)wParam, type);

				// USER - Incoming user ID
				if (type != NULL && strcmp(type, "USER") == 0)
				{
					char *data = NULL;
					if (!WinsockReadData((SOCKET)wParam, &data))
					{
						EndDialog(hWnd, 1);
						return TRUE;
					}

					/*
					 * Set user info for socket
					 */
					WinsockSetUser((SOCKET)wParam, nMaxUsers, data);

					/*
					 * Get user color for socket
					 */
					COLORREF crText;
					WinsockGetUser((SOCKET)wParam, nMaxUsers, NULL, &crText);

					/*
					 * Notify user connected
					 */
					char *szMsg = (char *)malloc(strlen(data) + 11);
					sprintf(szMsg, "%s Connected", data);
					AddNotify(GetDlgItem(hWnd, IDC_RICHEDIT), szMsg, crText);
					free(szMsg);

					/*
					 * Add user to connected users list
					 */
					SendDlgItemMessage(hWnd, IDC_USERS, LB_ADDSTRING, 0, (LPARAM)data);

					/*
					 * Send user connected message to all connected users
					 */
					char *szColor = (char *)malloc(16);
					sprintf(szColor, "%d", crText);

					char *szSend = (char *)malloc(strlen(data) + strlen(szColor) + 4);
					sprintf(szSend, "%s|.|%s", data, szColor);

					free(szColor);

					ChatSendAll("CONN", szSend, nMaxUsers);
					free(szSend);

					/*
					 * Broadcast users connected list
					 */
					WinsockBroadcast(nMaxUsers);
				}

				// MESG - Incoming message
				else if (type != NULL && strcmp(type, "MESG") == 0)
				{
					char *data = NULL;
					if (!WinsockReadData((SOCKET)wParam, &data))
					{
						EndDialog(hWnd, 1);
						return TRUE;
					}

					/*
					 * Get user info for socket
					 */
					COLORREF *crText = (COLORREF *)malloc(sizeof(COLORREF));
					char *szUserID = NULL;
					WinsockGetUser((SOCKET)wParam, nMaxUsers, &szUserID, crText);

					/*
					 * Resend message to all users
					 * Add message to rich edit
					 */
					ChatSendMsg(szUserID, *crText, data, nMaxUsers);
					AddChatMsg(GetDlgItem(hWnd, IDC_RICHEDIT), szUserID, *crText, data);

					free(data);
					free(crText);
				}

				free(type);
			}
			break;

		case FD_ACCEPT:
			/*
			 * Accept a user (or not, depending on if we're "full")
			 */
			WinsockAccept(nMaxUsers);
			break;

		case FD_CLOSE:
			/*
			 * Socket is closing
			 */
			{
				/*
				 * Get user data for socket that is closing
				 */
				COLORREF crText;
				char *szUserID = NULL;
				WinsockGetUser((SOCKET)wParam, nMaxUsers, &szUserID, &crText);

				/*
				 * Find user in list and remove him/her
				 */
				int nIndex = SendDlgItemMessage(hWnd, IDC_USERS, LB_FINDSTRING, -1, (LPARAM)szUserID);
				if (nIndex != LB_ERR)
					SendDlgItemMessage(hWnd, IDC_USERS, LB_DELETESTRING, nIndex, 0);

				/*
				 * Notify user that a user disconnected
				 */
				char *szMsg = (char *)malloc(strlen(szUserID) + 14);
				sprintf(szMsg, "%s Disconnected", szUserID);
				AddNotify(GetDlgItem(hWnd, IDC_RICHEDIT), szMsg, crText);

				free(szMsg);

				/*
				 * Send to all connected that the user disconnected
				 */
				char *szColor = (char *)malloc(16);
				sprintf(szColor, "%d", crText);

				char *szSend = (char *)malloc(strlen(szUserID) + strlen(szColor) + 4);
				sprintf(szSend, "%s|.|%s", szUserID, szColor);

				free(szColor);

				ChatSendAll("DISC", szSend, nMaxUsers);
				free(szSend);

				/*
				 * Close winsock and broadcast user list
				 */
				WinsockClose(nMaxUsers, (SOCKET)wParam);
				WinsockBroadcast(nMaxUsers);
			}
			break;
		}
		break;

	case WM_CLOSE:
		/*
		 * End winsock, free server ID
		 */
		if (szServerID != NULL)
			free(szServerID);

		WinsockEnd(nMaxUsers);
		EndDialog(hWnd, 1);
		break;

	default:
		return FALSE;
	}
	return TRUE;
}